package com.shiyi.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.shiyi.core.utils.encryption.EncryptUtils;
import com.shiyi.core.utils.result.Result;
import com.shiyi.core.vo.Menu;
import com.shiyi.core.vo.TokenUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


@Component
public class GateWayFilter implements GlobalFilter, Ordered {

    @Value("${gateway.excludeUrl}")
    private String excludeUrl;

    private  final Logger logger = LoggerFactory.getLogger(GateWayFilter.class);


    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        String url = getRequestUrl(request.getURI().toString());
        // 不是登录，则判断是否带token
        HttpHeaders headers = request.getHeaders();
        List<String> tokens = headers.get("token");
        TokenUser userByToken = null;
        String decodeBase64 = "";
        if (tokens != null && tokens.size() > 0) {
            String token  = tokens.get(0);
            decodeBase64 = EncryptUtils.decodeBase64(token);
            userByToken = (TokenUser) redisTemplate.opsForValue().get(decodeBase64);
        }
        // 非限制的url则放行
        if (existExcludeUrl(url, excludeUrl)) {
            this.gateWayLog(request, userByToken, url);
            return chain.filter(exchange);
        }
        if (userByToken != null) {
            redisTemplate.expire(decodeBase64, 30, TimeUnit.MINUTES);
            assert false;
            // 有菜单权限，则放行
            List<Menu> menus = userByToken.getMenus();
            if (menus != null && menus.size() > 0) {
                for (Menu menu : menus) {
                    if (url.equals(menu.getMenuUrl())) {
                        this.gateWayLog(request, userByToken, url);
                        return chain.filter(exchange);
                    }
                }
            }
        }
        this.gateWayLog(request, null, url);
        return Mono.defer(() -> {
            final ServerHttpResponse response = exchange.getResponse();
            HttpHeaders httpHeaders = response.getHeaders();
            httpHeaders.setContentType(MediaType.APPLICATION_JSON);
            Result<Object> result = new Result<>(403, "没有权限访问", null);
            byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
            return response.writeWith(Flux.just(buffer));//设置body
        });


    }

    private void gateWayLog(ServerHttpRequest request, TokenUser userByToken, String url) {
        String people = "未知";
        if (userByToken != null) {
            people = userByToken.toString();
        }
        // 获取ip
        InetSocketAddress ip = request.getRemoteAddress();
        // 获取url
        logger.error(people + " : " + ip + " : " + url);
    }

    private boolean existExcludeUrl(String url, String excludeUrl) {
        String[] split = excludeUrl.split(",");
        for (String s : split) {
            StringBuilder builder = new StringBuilder();
            String[] uri = s.trim().split("/");
            if (uri.length >= 3) {
                for (int i1 = 1; i1 <= 3; i1++) {
                    builder.append(uri[i1]).append(":");
                }
                String s1 = builder.substring(0, builder.length() - 1);
                if (s1.equals(url)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取url
     */
    private String getRequestUrl(String url) {
        StringBuilder builder = new StringBuilder();
        int i = url.indexOf(String.valueOf(9003));
        String uri = url.substring(i + 5);
        String[] split = uri.split("/");
        if (split.length >= 3) {
            for (int i1 = 0; i1 < 3; i1++) {
                builder.append(split[i1]).append(":");
            }
            return builder.substring(0, builder.length() - 1);
        }
        return null;
    }

    @Bean
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getHostName());
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
